package cn.edu.sgu.www.mhxysy.service.chongwu.impl;

import cn.edu.sgu.www.mhxysy.pager.Pager;
import cn.edu.sgu.www.mhxysy.consts.CustomMessages;
import cn.edu.sgu.www.mhxysy.dto.chongwu.ChongwuSkillDTO;
import cn.edu.sgu.www.mhxysy.entity.chongwu.Chongwu;
import cn.edu.sgu.www.mhxysy.entity.chongwu.ChongwuSkill;
import cn.edu.sgu.www.mhxysy.entity.chongwu.ChongwuSkillCategory;
import cn.edu.sgu.www.mhxysy.enums.AuthStatus;
import cn.edu.sgu.www.mhxysy.enums.ChongwuSkillTypes;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import cn.edu.sgu.www.mhxysy.mapper.chongwu.ChongwuMapper;
import cn.edu.sgu.www.mhxysy.mapper.chongwu.ChongwuSkillCategoryMapper;
import cn.edu.sgu.www.mhxysy.mapper.chongwu.ChongwuSkillMapper;
import cn.edu.sgu.www.mhxysy.pager.chongwu.ChongwuSkillPager;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.service.chongwu.ChongwuSkillService;
import cn.edu.sgu.www.mhxysy.util.MathUtils;
import cn.edu.sgu.www.mhxysy.util.ObjectUtils;
import cn.edu.sgu.www.mhxysy.util.StringUtils;
import cn.edu.sgu.www.mhxysy.vo.chongwu.ChongwuSkillVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

/**
 * @author 沐雨橙风ιε
 * @version 1.0
 */
@Service
public class ChongwuSkillServiceImpl implements ChongwuSkillService {

	private final ChongwuMapper chongwuMapper;
	private final ChongwuSkillMapper chongwuSkillMapper;
	private final ChongwuSkillCategoryMapper chongwuSkillCategoryMapper;

	@Autowired
	public ChongwuSkillServiceImpl(
			ChongwuMapper chongwuMapper,
			ChongwuSkillMapper chongwuSkillMapper,
			ChongwuSkillCategoryMapper chongwuSkillCategoryMapper) {
		this.chongwuMapper = chongwuMapper;
		this.chongwuSkillMapper = chongwuSkillMapper;
		this.chongwuSkillCategoryMapper = chongwuSkillCategoryMapper;
	}

	@Override
	public void validate(String chongwuId) {
		// 查询宠物可认证的技能
		List<ChongwuSkill> list = chongwuSkillMapper.getCanAuthedSkills(chongwuId);

		if (list.isEmpty()) {
			String message = "必须拥有“雷击、落岩、水攻、烈火、奔雷咒、泰山压顶、水漫金山、地狱烈火、上古灵符、水无常形”技能的召唤灵才可以被认证。";

			throw new GlobalException(ResponseCode.BAD_REQUEST, message);
		}
	}

	@Override
	public String cancelAuth(String chongwuId) {
		/*
		 * 取消法术认证
		 * 1、查询宠物已认证的技能：若查询结果为空，则抛出异常
		 * 2、删除已认证的技能
		 * 3、其他技能的位置向前推进1格
		 */

		/*
		 * 1、查询宠物已认证的技能：若查询结果为空，则抛出异常
		 */
		// 查询宠物已认证的技能
		QueryWrapper<ChongwuSkill> queryWrapper = new QueryWrapper<>();

		queryWrapper.eq("chongwu_id", chongwuId);
		queryWrapper.eq("auth_status", AuthStatus.YRZ.getValue());

		ChongwuSkill chongwuSkill = chongwuSkillMapper.selectOne(queryWrapper);

		if (chongwuSkill == null) {
			throw new GlobalException(ResponseCode.NOT_FOUND, "宠物没有已认证的技能。");
		}

		/*
		 * 2、删除已认证的技能
		 */
		chongwuSkillMapper.deleteById(chongwuSkill.getId());

		/*
		 * 3、其他技能的位置向前推进1格
		 */
		chongwuSkillMapper.decreaseLocations(chongwuId);


		// 返回宠物名称和等级拼接的字符串
		Chongwu chongwu = chongwuMapper.selectById(chongwuId);

		return chongwu.getName() + "(" + chongwu.getGrade() + "级)";
	}

	@Override
	public String study(String chongwuId, Integer skillId) {
		/*
		 * 学习技能
		 * 一、判断是否宠物已学习的技能、宠物技能数量是否上限
		 * 二、开始宠物学习技能流程
		 */

		/*
		 * 一、判断是否宠物已学习的技能、宠物技能数量是否上限
		 */
		// 1、检查是否重复技能
		QueryWrapper<ChongwuSkill> queryWrapper = new QueryWrapper<>();

		queryWrapper.eq("skill_id", skillId);
		queryWrapper.eq("chongwu_id", chongwuId);

		ChongwuSkill skill = chongwuSkillMapper.selectOne(queryWrapper);

		if (skill != null) {
			throw new GlobalException(ResponseCode.BAD_REQUEST, "已经学习了相同的技能，别浪费了~");
		}

		queryWrapper.clear();
		queryWrapper.eq("chongwu_id", chongwuId);

		List<ChongwuSkill> list = chongwuSkillMapper.selectList(queryWrapper);

		// 2、宠物技能数量是否上限
		int size = list.size();
		/*
		 * 宠物是否有已认证的技能
		 */
		boolean hasAuthedSkill = getAuthedSkill(chongwuId) == null;

		if ((hasAuthedSkill && size >= 13) || (!hasAuthedSkill && size >= 12)) {
			throw new GlobalException(ResponseCode.BAD_REQUEST, "该宠物的技能数量已经上限！");
		}

		/*
		 * 二、宠物学习技能
		 */
		String name = null; // 学习之前的技能名称
		int location = size + 1; // 学习技能的新位置

		// 宠物的技能数为3，1/10概率增加一个技能。相关成就：[顶出一片春天]
		if (location <= 3 || (location <= 4  && MathUtils.random(1, 10) == 5)) {
			// 为宠物添加一个技能
			ChongwuSkill chongwuSkill = new ChongwuSkill();

			chongwuSkill.setId(chongwuSkill.uuid());
			chongwuSkill.setSkillId(skillId);
			chongwuSkill.setLocation(location);
			chongwuSkill.setChongwuId(chongwuId);
			chongwuSkill.setAuthStatus(AuthStatus.WRZ.getValue());

			chongwuSkillMapper.insert(chongwuSkill);
		} else { // 宠物技能数量>=5，则随机替换未认证的技能
			/*
			 * 替换技能：随机替换宠物学习的一个未认证的技能
			 * 1、移除已认证的技能（防止已认证的技能被替换）
			 * 2、生成随机下标（模拟打书的随机性）、得到指定下标的元素
			 * 3、查询学习之前当前位置的的技能名称（反馈给前端）
			 * 4、修改宠物技能信息
			 */
			// 1、移除已认证的技能
			list.removeIf(new Predicate<ChongwuSkill>() {
				@Override
				public boolean test(ChongwuSkill chongwuSkill) {
					return AuthStatus.YRZ.getValue().equals(chongwuSkill.getAuthStatus());
				}
			});

			// 2、生成随机下标
			int random = MathUtils.random(0, list.size() - 1);

			// 得到指定下标的元素
			ChongwuSkill chongwuSkill = list.get(random);

			// 3、查询学习之前当前位置的的技能名称
			ChongwuSkillCategory category = chongwuSkillCategoryMapper.selectById(chongwuSkill.getSkillId());

			// 设置name为替换之前的技能名称
			name = category.getName();

			// 6、修改宠物技能信息
			UpdateWrapper<ChongwuSkill> updateWrapper = new UpdateWrapper<>();

			// 设置新的宠物技能类型ID
			updateWrapper.set("skill_id", skillId);

			// 通过宠物ID和宠物技能类型ID修改宠物技能信息
			updateWrapper.eq("chongwu_id", chongwuId);
			updateWrapper.eq("skill_id", chongwuSkill.getSkillId());

			int update = chongwuSkillMapper.update(updateWrapper.getEntity(), updateWrapper);

			if (update != 1) {
				throw new GlobalException(ResponseCode.BAD_REQUEST, "操作失败，请稍后重试...");
			}
		}

		return name; // 返回学习之前的技能名称
	}

	@Override
	public void replaceAuth(String chongwuId, Integer skillId) {
		/*
		 * 1、认证替换前的检查
		 */
		// 查询宠物已认证的技能
		QueryWrapper<ChongwuSkill> queryWrapper = new QueryWrapper<>();

		queryWrapper.eq("chongwu_id", chongwuId);
		queryWrapper.eq("auth_status", AuthStatus.YRZ.getValue());

		ChongwuSkill chongwuSkill = chongwuSkillMapper.selectOne(queryWrapper);

		if (chongwuSkill == null) {
			throw new GlobalException(ResponseCode.NOT_FOUND, "宠物没有已认证的技能。");
		}

		/*
		 * 2、修改已认证技能的宠物技能类型ID
		 */
		UpdateWrapper<ChongwuSkill> updateWrapper = new UpdateWrapper<>();

		updateWrapper.set("skill_id", skillId);
		updateWrapper.eq("id", chongwuSkill.getId());

		chongwuSkillMapper.update(updateWrapper.getEntity(), updateWrapper);
	}

	@Override
	public void authenticate(Integer location, String chongwuId) {
		/*
		 * 法术认证
		 * 1、判断技能是否存在：不存在则认证失败，抛出异常
		 * 2、判断技能是否可认证：不可认证则认证失败，抛出异常
		 * 3、判断技能的认证状态：已认证则认证失败，抛出异常
		 * 4、判断宠物是否已有认证的技能，每只宠物只能认证一个技能：若有，则认证失败，抛出异常
		 * 5、判断认证后宠物学习的技能数量是否大于13：大于13则认证失败，抛出异常
		 * 6、在其前面的技能整体后移1位
		 * 7、修改认证的技能位置及认证状态为1
		 * 8、为宠物随机添加一个未学习的低级技能
		 */

		/*
		 * 1、判断技能是否存在：不存在则认证失败，抛出异常
		 */
		// 获取宠物指定位置的技能信息
		QueryWrapper<ChongwuSkill> queryWrapper = new QueryWrapper<>();

		queryWrapper.eq("chongwu_id", chongwuId);
		queryWrapper.eq("location", location);

		ChongwuSkill selectOne = chongwuSkillMapper.selectOne(queryWrapper);

		// 查询结果大于1，数据异常
		if (selectOne == null){
			throw new GlobalException(ResponseCode.NOT_FOUND, "技能不存在，认证失败");
		}
		/*
		 * 2、判断技能是否可认证，不可认证则认证失败，抛出异常
		 */
		ChongwuSkillCategory category = chongwuSkillCategoryMapper.selectById(selectOne.getSkillId());
		String name = category.getName();

		// 技能无法认证
		if (category.getVerifiable() == 0) {
			String errorMessage = "技能<span class='blue'>" + name + "</span>无法认证，选择其他技能试试吧o_o";

			throw new GlobalException(ResponseCode.FORBIDDEN, errorMessage);
		}

		/*
		 * 3、判断技能的认证状态，已认证则认证失败，抛出异常
		 */
		if (AuthStatus.YRZ.getValue().equals(selectOne.getAuthStatus())) {
			String errorMessage = "技能<span style='color:blue;'>" + name + "</span>已经认证，少侠不要戏弄我了";

			throw new GlobalException(ResponseCode.FORBIDDEN, errorMessage);
		}

		/*
		 * 4、判断宠物是否已有认证的技能，每只宠物只能认证一个技能：若有，则认证失败，抛出异常
		 */
		// 查询宠物已认证的技能
		queryWrapper.clear();
		queryWrapper.eq("chongwu_id", chongwuId);
		queryWrapper.eq("auth_status", AuthStatus.YRZ.getValue());

		long size = chongwuSkillMapper.selectCount(queryWrapper);

		if (size > 0) {
			String errorMessage = "已经有一个已认证的技能了";

			throw new GlobalException(ResponseCode.CONFLICT, errorMessage);
		}

		/*
		 * 5、判断认证后宠物学习的技能数量是否大于13：大于13则认证失败，抛出异常
		 */
		// 查询宠物学习的技能总数
		QueryWrapper<ChongwuSkill> queryWrapper1 = new QueryWrapper<>();

		queryWrapper1.eq("chongwu_id", chongwuId);

		long total = chongwuSkillMapper.selectCount(queryWrapper1);

		// 判断count + 1 > 13
		if (total > 12) {
			String errorMessage = "宠物技能数量已达上限";

			throw new GlobalException(ResponseCode.BAD_REQUEST, errorMessage);
		}

		/*
		 * 6、在其前面的技能整体后移1位
		 */
		// 如果位置大于1，则其前面还有技能，修改其前面的技能位置+1
		if (location > 1) {
			chongwuSkillMapper.increaseLocations(chongwuId, location);
		}

		/*
		 * 7、修改认证的技能位置及认证状态为1
		 */
		UpdateWrapper<ChongwuSkill> updateWrapper = new UpdateWrapper<>();

		updateWrapper.eq("id", selectOne.getId());
		updateWrapper.eq("auth_status", AuthStatus.WRZ.getValue());

		updateWrapper.set("location", 1);
		updateWrapper.set("auth_status", AuthStatus.YRZ.getValue());

		int update = chongwuSkillMapper.update(updateWrapper.getEntity(), updateWrapper);

		if (update != 1) {
			throw new GlobalException(ResponseCode.BAD_REQUEST, "技能状态更新失败，请稍后重试~");
		}

		/*
		 * 8、为宠物随机添加一个未学习的低级技能
		 */
		// 查询宠物未学习的低级技能
		QueryWrapper<ChongwuSkillCategory> querywrapper = new QueryWrapper<>();

		querywrapper.notIn("id",
				"select skill_id from chongwu_skill where chongwu_id = " + chongwuId);
		querywrapper.eq("type", ChongwuSkillTypes.DJJN.getValue());
		querywrapper.eq("can_authed", 0);

		List<ChongwuSkillCategory> list = chongwuSkillCategoryMapper.selectList(querywrapper);

		// 得到随机下标
		int index = MathUtils.random(0, list.size() - 1);

		// 添加一个新的宠物技能
		ChongwuSkill chongwuSkill = new ChongwuSkill();

		chongwuSkill.setId(chongwuSkill.uuid());
		chongwuSkill.setLocation((int) (total + 1));
		chongwuSkill.setChongwuId(chongwuId);
		chongwuSkill.setSkillId(list.get(index).getId());
		chongwuSkill.setAuthStatus(AuthStatus.WRZ.getValue());

		chongwuSkillMapper.insert(chongwuSkill);
	}

	@Override
	public void insert(ChongwuSkillDTO chongwuSkillDTO) {
		ChongwuSkill chongwuSkill = toEntity(chongwuSkillDTO);

		chongwuSkill.setId(chongwuSkill.uuid());

		chongwuSkillMapper.insert(chongwuSkill);
	}

	@Override
	public void updateById(ChongwuSkillDTO chongwuSkillDTO) {
		ObjectUtils.requireNonNull(chongwuSkillDTO.getId(), CustomMessages.ID_NOT_NULL);

		ChongwuSkill chongwuSkill = toEntity(chongwuSkillDTO);

		chongwuSkillMapper.updateById(chongwuSkill);
	}

	@Override
	public ChongwuSkill getAuthedSkill(String chongwuId) {
		QueryWrapper<ChongwuSkill> queryWrapper = new QueryWrapper<>();

		queryWrapper.eq("chongwu_id", chongwuId);
		queryWrapper.eq("auth_status", AuthStatus.YRZ.getValue());

		return chongwuSkillMapper.selectOne(queryWrapper);
	}

	@Override
	public List<ChongwuSkillVO> getLearnedSkills(String chongwuId) {
		return chongwuSkillMapper.getLearnedSkills(chongwuId);
	}

	@Override
	public List<ChongwuSkill> getCanAuthedSkills(String chongwuId) {
		if (StringUtils.isNullOrEmpty(chongwuId)) {
			return new ArrayList<>();
		}

		return chongwuSkillMapper.getCanAuthedSkills(chongwuId);
	}

	@Override
	public Page<ChongwuSkill> selectByPage(ChongwuSkillPager pager) {
		QueryWrapper<ChongwuSkill> queryWrapper = new QueryWrapper<>();
		Page<ChongwuSkill> page = Pager.ofPage(pager);

		queryWrapper.eq(
				StringUtils.isNotEmpty(pager.getChongwuId()),
				"chongwu_id", pager.getChongwuId()
		);

		return chongwuSkillMapper.selectPage(page, queryWrapper);
	}

	public ChongwuSkill toEntity(ChongwuSkillDTO chongwuSkillDTO) {
		String id = chongwuSkillDTO.getId();
		Integer skillId = chongwuSkillDTO.getSkillId();
		String chongwuId = chongwuSkillDTO.getChongwuId();

		// 1、检查是否重复技能
		QueryWrapper<ChongwuSkill> queryWrapper = new QueryWrapper<>();

		queryWrapper.eq("skill_id", skillId);
		queryWrapper.eq("chongwu_id", chongwuId);
		queryWrapper.ne(StringUtils.isNotEmpty(id), "id", id);

		Long count = chongwuSkillMapper.selectCount(queryWrapper);

		if (count > 0) {
			throw new GlobalException(ResponseCode.BAD_REQUEST, "已经学习了相同的技能，别浪费了~");
		}

		queryWrapper.clear();
		queryWrapper.eq("chongwu_id", chongwuId);

		// 2、宠物技能数量是否上限
		Long total = chongwuSkillMapper.selectCount(queryWrapper);

		queryWrapper.clear();
		queryWrapper.eq("chongwu_id", chongwuId);
		queryWrapper.eq("auth_status", AuthStatus.YRZ.getValue());

		long selectCount = chongwuSkillMapper.selectCount(queryWrapper);

		if (total - selectCount >= 12) {
			throw new GlobalException(ResponseCode.BAD_REQUEST, "该宠物的技能数量已经上限！");
		}

		// 3、验证技能是否可认证：只有部分技能可以认证
		Integer authStatus = chongwuSkillDTO.getAuthStatus();

		if (AuthStatus.YRZ.getValue().equals(authStatus)) {
			ChongwuSkillCategory chongwuSkillCategory = chongwuSkillCategoryMapper.selectById(skillId);

			if (chongwuSkillCategory.getVerifiable() == 0) {
				throw new GlobalException(ResponseCode.BAD_REQUEST, "技能" + chongwuSkillCategory.getName() + "不可认证！");
			}
		}

		// 4、验证技能位置是否重复
		Integer location = chongwuSkillDTO.getLocation();

		queryWrapper.clear();

		queryWrapper.eq("location", location);
		queryWrapper.eq("chongwu_id", chongwuId);

		queryWrapper.ne(StringUtils.isNotEmpty(id), "id", id);

		count = chongwuSkillMapper.selectCount(queryWrapper);

		if (count > 0) {
			throw new GlobalException(ResponseCode.BAD_REQUEST, "技能位置重复！");
		}

		ChongwuSkill chongwuSkill = new ChongwuSkill();

		chongwuSkill.setId(id);
		chongwuSkill.setSkillId(skillId);
		chongwuSkill.setLocation(location);
		chongwuSkill.setChongwuId(chongwuId);
		chongwuSkill.setAuthStatus(authStatus);

		return chongwuSkill;
	}

}